package org.lds.hotkey.console.component;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.lds.hotkey.common.model.dto.ResultDTO;
import org.lds.hotkey.common.model.pojo.PageResult;
import org.lds.hotkey.common.util.RestUtil;
import org.lds.hotkey.common.util.ScheduledUtil;
import org.lds.hotkey.console.business.appinstance.model.request.AppInstanceBaseUpdateRequest;
import org.lds.hotkey.console.business.worker.model.request.WorkerBaseListPageRequest;
import org.lds.hotkey.console.business.worker.model.request.WorkerBaseUpdateRequest;
import org.lds.hotkey.console.business.worker.model.response.WorkerBaseResponse;
import org.lds.hotkey.console.business.worker.service.WorkerBaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
public class WorkerHealthRunner implements ApplicationRunner {
    @Autowired
    private WorkerBaseService workerBaseService;

    /**
     * key: id
     * value: 不健康的次数 默认为2
     */
    private Map<Long, Integer> noHealthIdCountMap = new HashMap<>();

    private Long id = 0L;

    @Override
    public void run(ApplicationArguments args) throws Exception {
        ScheduledUtil.defaultScheduled(() -> execute());
    }

    private void execute() {
        // 分页查询500条
        WorkerBaseListPageRequest request = new WorkerBaseListPageRequest();
        request.setGtId(id);
        request.setPageNum(1);
        request.setPageSize(500);
        request.setOrderByKey("id");
        request.setOrderByDesc(false);
        ResultDTO<PageResult<WorkerBaseResponse>> resultDTO = workerBaseService.listWorkerPage(request);
        if (!ResultDTO.isSuccess(resultDTO)) return;
        List<WorkerBaseResponse> workers = resultDTO.getData().getData();

        // 如果数据为空 重置查询
        if (CollectionUtils.isEmpty(workers)) {
            id = 0L;
            return;
        } else {
            id = workers.get(workers.size() - 1).getId();
        }

        // 检查ip:port是否健康
        workers.forEach(worker -> {
            boolean success = ResultDTO.isSuccess(RestUtil.post(worker.buildAddress() + "/health", null, new ParameterizedTypeReference<ResultDTO>() {}));
            if (success) {
                // 更新状态为已上线
                if(!worker.getEnable()) {
                    workerBaseService.updateWorker(WorkerBaseUpdateRequest.builder()
                            .id(worker.getId())
                            .enable(true)
                            .build());
                }
            } else {
                // 更新状态为已下线
                if(worker.getEnable()) {
                    offline(worker.getId());
                }
            }
        });
    }

    /**
     * 下线(尽量屏蔽网络波动的影响)
     * @param id
     */
    private void offline(Long id) {
        Integer count = noHealthIdCountMap.getOrDefault(id, 0) + 1;
        if (count >= 2) {
            noHealthIdCountMap.remove(id);

            workerBaseService.updateWorker(WorkerBaseUpdateRequest.builder()
                    .id(id)
                    .enable(false)
                    .build());
        } else {
            noHealthIdCountMap.put(id, count);
        }
    }
}
